我修過的課、看過的講義、寫過的作業,散落在雲端硬碟、iPad 筆記、印出來的 PDF 裡。要複習「迴歸分析」的時候,我得先想起它在哪個資料夾;更糟的是,我完全不知道自己學到哪裡了。
我要的不是筆記軟體,是一個能回答三個問題的網站:
參考對象是 algomaster.io 那種「roadmap → 課程 → 單元 → check-in」的體驗。接下來 30 天,我會從一個空目錄開始,把它做出來,然後推上雲端。
這是最容易做錯的一步。我列了三個候選:
| 選項 | 優 | 劣 |
|---|---|---|
| React + Vite + MDX | 生態完整、元件化 | 要顧建置、node_modules、每次改課文都要 rebuild |
| 靜態網站產生器(Hugo / Astro) | 內容導向、SEO 好 | 學新 DSL、互動元件要另外接 |
| 純靜態 + vanilla JS + 手寫 CSS | 零依賴、零建置、雙擊就開 | 沒有元件系統,要自己維持紀律 |
我選第三個。理由不是「vanilla 比較潮」,而是這個專案的真正瓶頸是寫課文,不是寫程式。任何讓「改一行課文要等 build」的東西,都會直接扣掉我持續寫內容的意願。
三條硬需求定案:
file:// 可直開:這條後來影響了非常多設計決策(Day 6 課文為什麼寫成 JS 字串、Day 3 為什麼不用 fetch 讀 JSON),Day 10 也因為 CSP 跟它打架而做了取捨。我認為這份清單比技術選型更重要。30 天的專案死因通常不是技術不夠,而是範圍失控。
learnpath/
├── index.html # 學習地圖(入口)
├── course.html # 一門課的章節總覽
├── chapter.html # 課文 + 測驗
├── css/style.css
├── js/
│ ├── models/ # curriculum.js(課綱)、progress.js(進度)
│ ├── views/ # map-view / course-view / lesson-view / nav-view
│ ├── controllers/ # home / course / chapter
│ └── lessons/ # 課文 HTML(每門課一個檔)
└── scripts/ # 驗證與工具(Node,不進瀏覽器)
三個資料夾對應三層,一眼看得出誰該碰誰。scripts/ 是開發期工具,不會被瀏覽器載入——這條界線之後救了我好幾次(Day 10 的驗證器就住在這裡)。
.gitignore# 第三方講義 PDF(2.3G、含版權素材)——只在本機當寫作參考
.reference/
# 免 root 安裝的工具(Day 20 會用到)
.tools/
# Python 快取
__pycache__/
*.pyc
.DS_Store
為什麼第一天就寫:我的參考素材資料夾有 2.3 GB 的第三方 PDF。如果不小心 git add . 進去,之後要從 git 歷史裡挖掉是件麻煩事,而且一旦推上 GitHub 就等於公開散布別人的著作。版權素材的 gitignore 要在第一次 commit 之前就存在,不是「之後再補」。
沒有框架幫你分層,最容易發生的事是「所有東西都寫在一個 main.js 裡」。我用三條規則約束自己,30 天沒有違反過:
| 層 | 可以做 | 不可以做 |
|---|---|---|
| Model | 提供資料與純查詢函式 | 碰 DOM |
| View | 收資料 → 回傳 HTML 字串/操作自己的 DOM | 讀 URL、寫 localStorage、決定導覽 |
| Controller | 讀 URL、組資料、傳 handler 給 View、寫 localStorage | 直接組 HTML |
具體長相:地圖 View 收到的是「已經算好 done/total/pct 的節點清單」,它不知道 Progress 存在。這條線在 Day 4 就會有第一次考驗,而它讓後面 20 天每次加功能都只需要動一層。
| 階段 | 天數 | 主題 |
|---|---|---|
| 核心產品 | 1–10 | 骨架與設計 token → 課綱 Model → SVG 學習地圖 → 課程頁與進度契約 → 課文頁 → 數學排版 → 測驗與寫作規格 → 遊戲化 → 雙層驗證 |
| 功能深化 | 11–20 | 深色模式 → 全站搜尋 → 統計數值表 → 章末總測驗 → 名詞對照 → PWA 離線 → 學習儀表板 → 教學動畫 → 效能與無障礙 → 內容自動化 |
| 上雲 | 21–30 | 平台選型 → CI → 首次部署 → 快取破壞 → 安全 header → S3+CloudFront IaC → 跨裝置同步 → Passkey 登入 → 可觀測性 → 回顧 |
第 27 天會打破今天的「不做後端」,但會帶一個條件:localStorage 仍然是 source of truth。到那時我會說清楚為什麼那個條件不能讓。
我不是第一次做這件事。上一版我犯了一個錯:為了「快速有內容」,寫了一支課文樣板產生器,用課綱關鍵字套進共用段落,一次生出兩百多課。結果是每一課讀起來都一樣、測驗的正確答案是 index % 3 算出來的假題。看起來很豐富,實際上一課都不能用,最後整批砍掉重寫。
所以本系列的第一條原則是:規格可以樣板化,內容不行。 Day 8 會把這個教訓寫成課文寫作規格。
今天沒有程式可驗,但有一件事要驗:
git init
git add .
git status --short # 確認 .reference/ 沒有出現在清單裡
git commit -m "chore: project skeleton"
git status --short 的輸出裡不該有任何 PDF。這就是今天的驗收標準。
今天定了三件事:純靜態 vanilla、MVC 自己分層、以及一份「不做」清單。
明天開始寫程式:HTML 骨架與 :root 設計 token。我會示範一個小技巧——把類別顏色當成資料而不是樣式,這個決定會在第 11 天(深色模式)以幾乎零成本的形式回報。
程式碼:
github.com/<user>/<repo>/tree/day01